#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <functional>
#include "Task.hpp"
#include "Channel.hpp"
using work_t=std::function<void()>;
enum
{
    OK=0,
    UsageError,
    PipeError,
    ForkError
};
class ProcessPool
{
    public:
    ProcessPool(int n,work_t w)
    :processnum(n),work(w)
    {
    }
    int InitProcessPool()
    {
        for(int i=0;i<processnum;++i)
        {
            int pipefd[2];
            int n=pipe(pipefd);
            if(n<0)
                return PipeError;
            pid_t id=fork();
            if(id<0)
                return ForkError;
            if(id==0)
            {
                std::cout<<getpid()<<",child close history fd:";
                //关闭历史遗留进程fd，因为每增加一个子进程，它都会拥有与父进程的读写端以及与其他子进程的写端
                for(auto& c:channels)
                {
                    std::cout<<c.wFd()<<" ";
                    c.Close();
                }
                std::cout<<"over"<<std::endl;
                ::close(pipefd[1]);//关闭对父进程的写端
                dup2(pipefd[0],0);
                work();//执行work，一直等待父进程的指令，然后执行
                ::exit(0);//父进程关闭写端，退出
            }
            //这里为父进程
            ::close(pipefd[0]);
            channels.emplace_back(pipefd[1],id);
        }
        return OK;
    }

    void Dispatcher()
    {
        int who=0;
        int num=20;//一次执行20个任务
        while(num--)
        {
            int task=TM.SelectTask();//随机选择一个任务
            Channel& curr=channels[who++];
            who%=channels.size();
            std::cout << "######################" << std::endl;
            std::cout << "send " << task << " to " << curr.Name() << ", 任务还剩: " << num << std::endl;
            std::cout << "######################" << std::endl;
            curr.Send(task);
            sleep(1);
        }
    }

    void CleanProcesPool()
    {
        for(auto& c:channels)//关闭对每一个子进程的写端，子进程会自动退出，然后父进程等待，回收子进程
        {
            c.Close();
            pid_t rid=waitpid(c.Id(),nullptr,0);
            if(rid>0)
            {
                std::cout << "child " << rid << " wait ... success" <<std::endl;
            }
        }
    }

    void DebugPrint()
    {
        for(auto& c:channels)
            std::cout<<c.Name()<<std::endl;
    }

    ~ProcessPool()
    {

    }
    private:
    std::vector<Channel> channels;
    int processnum;
    work_t work;
};